package com.gagakuai.engine.impl.context;

import com.gagakuai.engine.ProcessEngineConfiguration;
import com.gagakuai.engine.impl.cfg.ProcessEngineConfigurationImpl;
import com.gagakuai.engine.impl.interceptor.CommandContext;
import com.gagakuai.engine.impl.runtime.InterpretableExecution;

import java.util.Stack;

/*
 * @program: common-starters
 * @description: 上下文类
 * @author: houhong
 * @create: 2023-01-01 23:31
 */
public class Context {

    /*
     * 命令上下文栈
     */
    protected static ThreadLocal<Stack<CommandContext>> commandContextThreadLocal = new ThreadLocal<>();
    /*
     * 配置类下文栈
     */
    protected static ThreadLocal<Stack<ProcessEngineConfiguration>> processEngineConfigurationStackThreadLocal = new ThreadLocal<>();
    /*
     * 执行实体上下文栈
     */
    protected static ThreadLocal<Stack<ExecutionContext>> executionContextStackThreadLocal = new ThreadLocal<>();

    public static CommandContext getCommandContext() {

        Stack<CommandContext> stack = getStack(commandContextThreadLocal);

        return stack.isEmpty() ? stack.peek() : null;
    }

    public static void setProcessEngineConfiguration(ProcessEngineConfiguration configuration) {
        getStack(processEngineConfigurationStackThreadLocal).push(configuration);
    }

    public static ProcessEngineConfiguration getProcessEngineConfiguration() {

        Stack<ProcessEngineConfiguration> stack = getStack(processEngineConfigurationStackThreadLocal);

        return stack.isEmpty() ? stack.peek() : null;
    }

    public static void setCommandContext(CommandContext context) {
        getStack(commandContextThreadLocal).push(context);
    }

    public static void setExecutionContext(InterpretableExecution execution) {
        getStack(executionContextStackThreadLocal).push(new ExecutionContext(execution));
    }

    public static void removeExecutionContext() {
        getStack(executionContextStackThreadLocal).pop();
    }
    protected static <T> Stack<T> getStack(ThreadLocal<Stack<T>> threadLocal) {

        Stack<T> ts = threadLocal.get();
        if (ts == null) {
            ts = new Stack<>();
            threadLocal.set(ts);
        }
        return ts;
    }

}